﻿' One group in a row. Contains a collection of DiagramNode objects 
' that are arranged within the group.
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Windows.Controls
Imports System.Windows
Imports System.Windows.Media

''' <summary>
''' Group in a row that contains node objects.
''' </summary>
Public Class DiagramGroup
    Inherits FrameworkElement

#Region " fields "

    ' Space between each node.
    Private Const NodeSpace As Double = 10

    ' Location of the group, relative to the row.
    Private m_location As Point = New Point()

    ' List of nodes in the group.
    Private m_nodes As New List(Of DiagramNode)

#End Region

#Region " properties "

    ''' <summary>
    ''' Location of the group, relative to the row.
    ''' </summary>
    Public Property Location() As Point
        Get
            Return m_location
        End Get
        Set(ByVal value As Point)
            m_location = value
        End Set
    End Property

    ''' <summary>
    ''' List of nodes in the group.
    ''' </summary>
    Public ReadOnly Property Nodes() As ReadOnlyCollection(Of DiagramNode)
        Get
            Return New ReadOnlyCollection(Of DiagramNode)(m_nodes)
        End Get
    End Property

#End Region

#Region " overrides "

    Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
        ' Let each node determine how large they want to be.
        Dim size As Size = New Size(Double.PositiveInfinity, Double.PositiveInfinity)
        For Each node In m_nodes
            node.Measure(size)
        Next
        ' Return the total size of the group.
        Return Me.ArrangeNodes(False)
    End Function

    Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
        ' Arrange the nodes in the group, return the total size.
        Return ArrangeNodes(True)
    End Function

    Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
        Get
            Return Nodes.Count
        End Get
    End Property

    Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
        ' Return the requested node.
        Return Nodes(index)
    End Function


#End Region

    ''' <summary>
    ''' Add the node to the group.
    ''' </summary>
    Public Sub Add(ByVal node As DiagramNode)
        Me.m_nodes.Add(node)
        Me.AddVisualChild(node)
    End Sub

    ''' <summary>
    ''' Remove all nodes from the group.
    ''' </summary>
    Public Sub Clear()
        For Each node In Nodes
            Me.RemoveVisualChild(node)
        Next
        m_nodes.Clear()
    End Sub

    ''' <summary>
    ''' Reverse the order of the nodes.
    ''' </summary>
    Public Sub Reverse()
        Nodes.Reverse()
    End Sub

    ''' <summary>
    ''' Arrange the nodes in the group, return the total size.
    ''' </summary>
    Private Function ArrangeNodes(ByVal arrange As Boolean) As Size
        ' Position of the next node.
        Dim pos As Double = 0

        ' Bounding area of the node.
        Dim bounds As Rect = New Rect()

        ' Total size of the group.
        Dim totalSize As Size = New Size(0, 0)

        For Each node In Nodes
            ' Node location.
            bounds.X = pos
            bounds.Y = 0

            ' Node size.
            bounds.Width = node.DesiredSize.Width
            bounds.Height = node.DesiredSize.Height

            ' Arrange the node, save the location.
            If arrange Then
                node.Arrange(bounds)
                node.Location = bounds.TopLeft
            End If

            ' Update the size of the group.
            totalSize.Width = pos + node.DesiredSize.Width
            totalSize.Height = Math.Max(totalSize.Height, node.DesiredSize.Height)
            pos += (bounds.Width + NodeSpace)
        Next
        Return totalSize
    End Function


End Class
